#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <iohelper.h>

off_t io_get_size(const char* fn)
{
    struct stat sb;

    if(stat(fn, &sb) < 0)
        return 0;

    return sb.st_size;
}

bool io_set_size(int fd, off_t len)
{
    return ftruncate(fd, len) == 0;
}

bool io_goto(int fd, off_t pos)
{
    if (pos == (off_t) -1)
        return lseek(fd, 0, SEEK_END) >= 0;
    return lseek(fd, pos, SEEK_SET) == pos;
}

int io_read_safe(int fd, void *p, int size)
{
    char *buf = (char *) p;
    int   read_bytes = 0, r;

    while (read_bytes < size) {
        int remain_bytes = size - read_bytes;
        r = read(fd, buf + read_bytes, remain_bytes);
        if (r > 0)
            read_bytes += r;
        else if ((r == 0)
                 || (errno != EINTR && errno != EAGAIN))
            break;
    }

    return read_bytes;
}

int io_write_safe(int fd, const void *p, int size)
{
    char *buf = (char *) p;
    int   write_bytes = 0, r;

    while (write_bytes < size) {
        int remain_bytes = size - write_bytes;
        r = write(fd, buf + write_bytes, remain_bytes);
        if (r > 0)
            write_bytes += r;
        else if ((r == 0)
                 || (errno != EINTR && errno != EAGAIN))
            break;
    }

    return write_bytes;
}

DyBuf *io_read_file(const char *fn)
{
    off_t size = io_get_size(fn);

    if (size <= 0 || size >= 0x7fffffff)
        return NULL;

    int fd = open(fn, O_RDONLY);
    if (fd < 0)
        return NULL;

    DyBuf *dybuf = new DyBuf(size);

    char *p = dybuf->get_buf_end();
    if (io_read_safe(fd, p, size) != size) {
        delete dybuf;
        close(fd);
        return NULL;
    }
    close(fd);
    dybuf->buf_right += size;
    return dybuf;
}
